package com.lmt;

import com.alibaba.fastjson.JSON;
import com.lmt.base.BaseRequest;
import com.lmt.base.ResultData;
import com.lmt.util.AesRequestUtil;
import com.lmt.util.SystemConstant;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * Date 2018/07/17
 *
 * @author MT-Lin
 */
@Aspect
@Component
public class WebApiAop {

    private final static Logger logger = LoggerFactory.getLogger(WebApiAop.class);

    @Value("${enableEncrypt}")
    private boolean enableEncrypt;

    @Pointcut("execution(public * com.lmt.api.*.*(..))")
    public void webApiAopPointCut() {
    }

    /**
     * 增强方法，获取并修改目标函数的参数（解密请求的数据、加密响应的数据）
     * @param proceedingJoinPoint 获取连接点数据
     * @return 参数
     * @throws Throwable 异常
     */
    @Around("webApiAopPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object object;
        Object[] args = proceedingJoinPoint.getArgs();
        if (enableEncrypt) {
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof BaseRequest) {
                    String encryptData = ((BaseRequest) args[i]).getEncryptData();
                    args[i] = JSON.parseObject(AesRequestUtil.defaultAseDecrypt(encryptData), args[i].getClass());
                }
            }
            object = proceedingJoinPoint.proceed(args);
            if (object instanceof ResultData) {
                ((ResultData) object).setEncryptData(AesRequestUtil.defaultAseEncrypt(
                        new String(JSON.toJSONString(object).getBytes(), SystemConstant.CHARSET_UTF8)
                )).setData(null).setCode(null);
            }
        } else {
            object = proceedingJoinPoint.proceed(args);
        }
        return object;
    }

    @Before("webApiAopPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 请求方法
        logger.info("request method = {}", request.getMethod());
        // 类
        logger.info("class = {}", joinPoint.getSignature().getDeclaringTypeName());
        // 方法
        logger.info("method name = {}", joinPoint.getSignature().getName());
        // 参数
        logger.info("parameters = {}", joinPoint.getArgs());
        // URL
        String url = request.getRequestURI();
        logger.info("url = {}", url);
        String tokenId = request.getHeader("Authorization");
        Object[] args = joinPoint.getArgs();
        if (args.length > 0){
            for (Object arg : args){
                if (arg instanceof BaseRequest){
                    ((BaseRequest) arg).setTokenId(tokenId);
                }
            }
        }
        if (null == tokenId) {
            if (!SystemConstant.LOGIN_INTERCEPTOR_EXCLUDE_URL.contains(url)){
                logger.error("tokenId is NULL，用户还未登录");
            }
        } else {
            logger.info("tokenId is " + tokenId);
        }
    }

    @After("webApiAopPointCut()")
    public void doAfter() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("url = {} end of execution", request.getRequestURL());
    }

    @AfterReturning(returning = "object", pointcut = "webApiAopPointCut()")
    public void doAfterReturn(Object object) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String url = request.getRequestURL().toString();
        if (null == object) {
            if (!url.endsWith(SystemConstant.DOWNLOAD_FILE_URL)) {
                logger.error("The data returned NULL");
            }
        } else {
            logger.info("response = {}", object.toString());
        }
    }
}
